package com.example.wxback.config.filter;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.wxback.config.exception.CommonJsonException;
import com.example.wxback.redis.JedisDao;
import com.example.wxback.service.TokenService;
import com.example.wxback.session.SessionUserInfo;
import com.example.wxback.util.CommonUtil;
import com.example.wxback.util.StringTools;
import com.example.wxback.util.constants.ErrorEnum;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.UUID;

/**
 * @author heeexy
 */
@Component
@Slf4j
public class RequestFilter extends OncePerRequestFilter implements Filter {

    @Autowired
    TokenService tokenService;

    @Autowired
    private JedisDao jedisDao;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            boolean isIgnoreUrl = false;
            log.info("RequestFilter-doFilterInternal-{}", request.getServletPath());
            log.info("RequestFilter-doFilterInternal-{}", request.getHeader("token"));
            if (request.getServletPath().contains("/login/auth") ||
                    request.getServletPath().contains("/wx/user/register") ||
                    request.getServletPath().contains("/wx/user/masterlogin") ||
                    request.getServletPath().contains("/wx/user/login") ||
                    request.getServletPath().contains("/wx/message/upload") ||
                    request.getServletPath().contains("/config/")
            ) {
                isIgnoreUrl = true;
            }
            //每个请求记录一个traceId,可以根据traceId搜索出本次请求的全部相关日志
            MDC.put("traceId", UUID.randomUUID().toString().replace("-", "").substring(0, 12));
            //使request中的body可以重复读取 https://juejin.im/post/6858037733776949262#heading-4
            request = new ContentCachingRequestWrapper(request);
            if (isIgnoreUrl) {
                log.info("RequestFilter-doFilterInternal-{}", "过滤接口");
            } else {
                setUsername(request);
                setProductId(request);
            }
            filterChain.doFilter(request, response);
        } catch (CommonJsonException e) {
            log.info("RequestFilter-doFilterInternal-CommonJsonException", e.getResultJson().toString());
            PrintWriter writer = null;
            OutputStreamWriter osw = null;
            try {
                osw = new OutputStreamWriter(response.getOutputStream(),
                        "UTF-8");
                writer = new PrintWriter(osw, true);
                writer.write(e.getResultJson().toJSONString());
                writer.flush();
                writer.close();
                osw.close();
            } catch (Exception exception) {

            } finally {
                if (null != writer) {
                    writer.close();
                }
                if (null != osw) {
                    osw.close();
                }
            }
            return;
        } finally {
            //清理ThreadLocal
            MDC.clear();
        }
    }

    /**
     * 将url参数中的productId放入ThreadLocal
     */
    private void setProductId(HttpServletRequest request) {
        String productIdStr = request.getParameter("productId");
        if (!StringTools.isNullOrEmpty(productIdStr)) {
            log.debug("url中productId = {}", productIdStr);
            MDC.put("productId", productIdStr);
        }
    }

    private void setUsername(HttpServletRequest request) {
        //通过token解析出username
        String token = request.getHeader("token");
        if (!StringTools.isNullOrEmpty(token)) {
            if (StringUtils.isBlank(jedisDao.getValue(token))) {
                throw new CommonJsonException(ErrorEnum.E_20011);
            }
            MDC.put("token", token);
            try {
                SessionUserInfo sessionUserInfo = tokenService.getUserInfo();
                if (sessionUserInfo != null) {
                    String username = sessionUserInfo.getUsername();
                    MDC.put("username", username);
                    request.setAttribute("users", sessionUserInfo);
                } else {
                    throw new CommonJsonException(ErrorEnum.E_20011);
                }
            } catch (CommonJsonException e) {
                log.info("无效的token:{}", token);
                throw e;
            }
        } else {
            throw new CommonJsonException(ErrorEnum.E_20011);
        }
    }
}
